#! python
# -*- coding: utf-8 -*-
from math import copysign, floor
from copy import deepcopy

import random; random.seed(44)
from time import time

from noise import get_around_pixels as get_around_pixels_c
from objects_on_map import Pixel, get_around_pixels
from noise_generator import MATRIX


DEBUG = False


def gauss_random(a=2.7, b=2.6):

    random_value = random.gauss(0, 1)
    random_value = random_value if random_value > 0 else -random_value
    #print random_value
    boolean_value = a > random_value > b

    return boolean_value


def make_treasure(altitude_noise, chrome_noise, silicone_noise, pegmatite_noise):
    pixel = Pixel()

    def gold():

        def get_luck(pixel_config):
            around_step = 4
            luck = 0

            pixels_near_center = get_around_pixels_c(pixel_config, around_step)

            for one_pixel in pixels_near_center:

                value_in_noise_list = altitude_noise[one_pixel[1]][one_pixel[0]]
                if value_in_noise_list < 10:
                    luck += 1
                else:
                    luck -= (around_step * 2) ** 2

            # print "luck = %d" % luck
            return luck > 60

        y = 0

        for y_height in altitude_noise:
            x = 0

            #print float(y) / float(len(altitude_noise)) * 100
            for x_pixel_altitude in y_height:
                if x_pixel_altitude < 10:
                    # Rock pixel
                    if x_pixel_altitude > 0:

                        if x_pixel_altitude > 5:
                            if gauss_random(a=2.85, b=2.55):
                                pixel.x = x
                                pixel.y = y

                                # print get_luck(pixel)
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 1) == 0:
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10

                        if x_pixel_altitude == 5:
                            if gauss_random(a=2.85, b=2.75):
                                pixel.x = x
                                pixel.y = y
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 2) == 0:
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10

                        if x_pixel_altitude == 4:
                            if gauss_random(a=2.90, b=2.75):
                                pixel.x = x
                                pixel.y = y
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 2) == 0:
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10

                        if x_pixel_altitude == 3:
                            if gauss_random(a=3.0, b=2.75):
                                pixel.x = x
                                pixel.y = y
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 3) == 0:
                                        # Make much gold
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10

                        if x_pixel_altitude == 2:
                            if gauss_random(a=3.0, b=2.8):
                                pixel.x = x
                                pixel.y = y
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 5) == 0:
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10

                        if x_pixel_altitude == 1:
                            if gauss_random(a=2.95, b=2.8):
                                pixel.x = x
                                pixel.y = y
                                # Make Treasure!
                                if get_luck(pixel):

                                    if random.randint(0, 9) == 0:
                                        altitude_noise[y][x] = 11
                                    else:
                                        altitude_noise[y][x] = 10
                    # Dirt
                    else:
                        #print "luck = %d" % luck
                        if gauss_random(a=3.35, b=3.2):
                            luck = 0

                            pixel.x = x
                            pixel.y = y

                            around_step = 5
                            pixels_near_center = get_around_pixels_c(pixel, around_step)

                            for one_pixel in pixels_near_center:

                                value_in_noise_list = altitude_noise[one_pixel[1]][one_pixel[0]]
                                if value_in_noise_list == 10:
                                    luck += 1

                            if luck == 0:
                                altitude_noise[y][x] = 10

                x += 1
            y += 1

    def emerald():
        around_step = 5

        y = 0

        for y_height in chrome_noise:
            x = 0

            for x_pixel_chrome_iron in y_height:
                # Chrome pixel selected
                if x_pixel_chrome_iron == 0:
                    luck = 0
                    pixel.x = x
                    pixel.y = y

                    value_in_altitude_list = altitude_noise[y][x]

                    if value_in_altitude_list in (3, 4, 5, 6, 7, 8):
                        if value_in_altitude_list == 8:
                            b = 1.0
                        if value_in_altitude_list == 7:
                            b = 1.1
                        if value_in_altitude_list == 6:
                            b = 1.3
                        if value_in_altitude_list == 5:
                            b = 2.1
                        if value_in_altitude_list == 4:
                            b = 2.4
                        if value_in_altitude_list == 3:
                            b = 2.7

                        if gauss_random(a=3.0, b=b):
                            if DEBUG:
                                print pixel.x, pixel.y

                            pixels_near_center = get_around_pixels_c(pixel, around_step)

                            for one_pixel in pixels_near_center:
                                x_pixel_inside_square = one_pixel[0]
                                y_pixel_inside_square = one_pixel[1]

                                value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                                if value_in_altitude_list == 21:
                                    luck += 1

                            if luck == 0:
                                altitude_noise[y][x] = 21

                x += 1
            y += 1

    def aquamarine():
        around_step = 5
        aquamarine_centers = []

        y = 0

        for y_height in pegmatite_noise:
            x = 0

            for x_pixel_pegmatite in y_height:
                # Pegmatite pixel selected
                if x_pixel_pegmatite == 1:
                    luck, silicone_counter = 0, 0
                    pixel.x = x
                    pixel.y = y

                    value_in_altitude_list = altitude_noise[y][x]
                    value_in_chrome_iron = chrome_noise[y][x]

                    silicone_around_pixels = get_around_pixels(pixel, around_step)

                    for silicone in silicone_around_pixels:
                        x_pixel_inside_square = silicone[0]
                        y_pixel_inside_square = silicone[1]

                        value_in_silicone_list = silicone_noise[y_pixel_inside_square][x_pixel_inside_square]
                        if value_in_silicone_list != 0:
                            silicone_counter += 1

                    # 1st ground line and iron area
                    if value_in_altitude_list == 1 and value_in_chrome_iron in (0, 1) and silicone_counter == 0:

                        aquamarine_centers.append([x, y])

                x += 1
            y += 1

        aquamarines_corrosion = []
        around_step = 1

        for one_aquamarine_center in aquamarine_centers:
            pixel.x = one_aquamarine_center[0]
            pixel.y = one_aquamarine_center[1]

            pixels_near_center = get_around_pixels(pixel, around_step)

            for one_pixel in pixels_near_center:
                x_pixel_inside_square = one_pixel[0]
                y_pixel_inside_square = one_pixel[1]

                value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                if value_in_altitude_list in (1, 2) and random.randint(0, 12) == 0:
                    aquamarines_corrosion.append([x_pixel_inside_square, y_pixel_inside_square])

        for corrosion_pixel in aquamarines_corrosion:
            pixel.x = corrosion_pixel[0]
            pixel.y = corrosion_pixel[1]
            #altitude_noise[pixel.y][pixel.x] = "Pick"

            luck = 0

            around_step = random.randint(2, 6)

            pixels_near_center = get_around_pixels(pixel, around_step)

            for one_pixel in pixels_near_center:
                x_pixel_inside_square = one_pixel[0]
                y_pixel_inside_square = one_pixel[1]

                value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                if value_in_altitude_list == 24:
                    luck += 1

            if luck == 0 and random.randint(0, 3) == 0:
                altitude_noise[pixel.y][pixel.x] = 24

    def diamond():
        around_step = 1
        diamonds_position = []

        y = 0

        for y_height in altitude_noise:
            x = 0

            for x_pixel_altitude in y_height:
                # Rock pixel
                if x_pixel_altitude > 5:
                    luck = 0

                    pixel.x = x
                    pixel.y = y

                    pixels_near_center = get_around_pixels(pixel, around_step)

                    for one_pixel in pixels_near_center:

                        value_in_noise_list = altitude_noise[one_pixel[1]][one_pixel[0]]

                        if value_in_noise_list != x_pixel_altitude:
                            luck += 1

                    if luck == 0 or x_pixel_altitude in (7, 8):
                        diamonds_position.append([x, y])

                x += 1
            y += 1

        if len(diamonds_position) > 0:
            # Diamond coefficient
            base_diamond_number_for_map = float(MATRIX[0] * MATRIX[1]) / float(40000)

            if 1 > base_diamond_number_for_map > 0.4: base_diamond_number_for_map = 1
            else:
                if random.randint(0, 4) == 0: base_diamond_number_for_map = 1
            if DEBUG:
                print "base_diamond_number_for_map: %d" % base_diamond_number_for_map

            k = 1.0

            # Random Unluck 1/3
            if random.randint(0, 2) == 0 and base_diamond_number_for_map > 0: base_diamond_number_for_map -= 1
            if DEBUG:
                print "Diamond Number: %d" % base_diamond_number_for_map

            diamonds_count = int(base_diamond_number_for_map + floor(copysign(random.gauss(0, k - 0.5), 0)))

            if DEBUG:
                print "diamonds_position length:", len(diamonds_position)
                print "diamonds_position:", diamonds_position
                print "diamonds_count=", diamonds_count

            diamond_pixel = Pixel()
            around_step = 10

            while diamonds_count > 0:
                put_diamond = True

                position = random.choice(diamonds_position)

                diamond_pixel.x = position[0]
                diamond_pixel.y = position[1]
                # if DEBUG:
                #     print position

                pixels_near_center = get_around_pixels(diamond_pixel, around_step)

                for one_pixel in pixels_near_center:
                    # if DEBUG:
                    #     print one_pixel

                    if altitude_noise[one_pixel[1]][one_pixel[0]] == 20:
                        #print "Near diamond!"
                        put_diamond = False
                        diamonds_position.remove(position)

                        if len(diamonds_position) == 0:
                            diamonds_count = 0

                if DEBUG:
                    print "put_diamond=", put_diamond
                if put_diamond:
                    diamonds_count -= 1
                    altitude_noise[diamond_pixel.y][diamond_pixel.x] = 20
                    diamonds_position.remove(position)

    def ruby():
        around_step = 15

        y = 0

        for y_height in silicone_noise:
            x = 0

            for x_pixel_silicone in y_height:
                # Silicone pixel selected
                if x_pixel_silicone == 1:
                    luck = 0
                    pixel.x = x
                    pixel.y = y

                    value_in_altitude_list = altitude_noise[y][x]

                    if value_in_altitude_list == 2:
                        if gauss_random(a=3.5, b=2.7):

                            pixels_near_center = get_around_pixels_c(pixel, around_step)

                            for one_pixel in pixels_near_center:
                                x_pixel_inside_square = one_pixel[0]
                                y_pixel_inside_square = one_pixel[1]

                                value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                                if value_in_altitude_list in (21, 22, 23):
                                    luck += 1

                            if luck == 0:
                                altitude_noise[y][x] = 23

                x += 1
            y += 1

    def saphire():

        y = 0

        for y_height in silicone_noise:
            x = 0

            for x_pixel_silicone in y_height:
                # Titan pixel selected
                if x_pixel_silicone == 2:
                    around_step = 1
                    border_count = 0
                    saphire_count = 0
                    chrome_count = 0

                    pixel.x = x
                    pixel.y = y

                    value_in_altitude_list = altitude_noise[y][x]

                    if value_in_altitude_list in (1, 2, 3):
                        pixels_near_center = get_around_pixels_c(pixel, around_step)

                        for one_pixel in pixels_near_center:
                            x_pixel_inside_square = one_pixel[0]
                            y_pixel_inside_square = one_pixel[1]

                            other_value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                            if other_value_in_altitude_list < 10 and copysign(value_in_altitude_list - other_value_in_altitude_list, 0) == 1:
                                border_count += 1

                        around_step = 10
                        for one_pixel in get_around_pixels_c(pixel, around_step):
                            x_pixel_inside_square = one_pixel[0]
                            y_pixel_inside_square = one_pixel[1]

                            other_value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                            if other_value_in_altitude_list == 22:
                                saphire_count += 1

                        around_step = 6
                        for one_pixel in get_around_pixels_c(pixel, around_step):
                            x_pixel_inside_square = one_pixel[0]
                            y_pixel_inside_square = one_pixel[1]

                            value_in_chrome_noise = chrome_noise[y_pixel_inside_square][x_pixel_inside_square]

                            if value_in_chrome_noise == 0:
                                chrome_count += 1

                        if border_count > 0 and saphire_count == 0 and chrome_count == 0:
                            altitude_noise[y][x] = 22

                x += 1
            y += 1

    def pickaxe():
        around_step = 4
        rock_pixel_types = range(1, 9)
        pickaxe_centers = []

        y = 0

        for y_array_in_altitude in altitude_noise[::4]:
            x = 0

            for pixel_altitude in y_array_in_altitude[::4]:

                # Ground pixel selected
                if pixel_altitude in rock_pixel_types:

                    treasure_and_goods_count = 0

                    pixel.x = x
                    pixel.y = y

                    pixels_near_center = get_around_pixels(pixel, around_step)
                    for one_pixel in pixels_near_center:
                        x_pixel_inside_square = one_pixel[0]
                        y_pixel_inside_square = one_pixel[1]

                        value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]
                        # Not in dirt place pickaxe
                        if value_in_altitude_list > 9 or value_in_altitude_list == 0:
                            treasure_and_goods_count += 1

                    if treasure_and_goods_count == 0:
                        pickaxe_centers.append([pixel.x, pixel.y])
                        #altitude_noise[pixel.y][pixel.x] = 30
                        #print rock_count #print "packaxe now!@!"

                x += 4
            y += 4

        if DEBUG:
            print "Length: %d" % len(pickaxe_centers)

        pickaxe_collision = []
        around_step = 1

        for one_pickaxe_center in pickaxe_centers:
            pixel.x = one_pickaxe_center[0]
            pixel.y = one_pickaxe_center[1]

            pixels_near_center = get_around_pixels(pixel, around_step)

            random_pixel = random.choice(pixels_near_center)

            pixel.x = random_pixel[0]
            pixel.y = random_pixel[1]

            pickaxe_collision.append([pixel.x, pixel.y])

        while len(pickaxe_collision) > 0:
            around_step = random.randint(15, 22)

            random_element_in_pickaxe_collision = random.choice(pickaxe_collision)

            pixel.x = random_element_in_pickaxe_collision[0]
            pixel.y = random_element_in_pickaxe_collision[1]

            value_in_altitude_list = altitude_noise[pixel.y][pixel.x]
            max_random = 8 if value_in_altitude_list in xrange(1, 3) else 4

            if random.randint(0, max_random) == 0:
                luck = 0

                pixels_near_center = get_around_pixels(pixel, around_step)

                for one_pixel in pixels_near_center:
                    x_pixel_inside_square = one_pixel[0]
                    y_pixel_inside_square = one_pixel[1]

                    value_in_altitude_list = altitude_noise[y_pixel_inside_square][x_pixel_inside_square]

                    if value_in_altitude_list > 9 and value_in_altitude_list != 31:
                        luck += 1

                if luck == 0:
                    altitude_noise[pixel.y][pixel.x] = 30

            pickaxe_collision.remove(random_element_in_pickaxe_collision)

    def measure(function):
        start_time = time()
        function()
        end_time = time() - start_time
        print("%s %f" % (function.__name__, end_time))

    measure(diamond)
    measure(emerald)
    measure(saphire)
    measure(ruby)
    measure(aquamarine)
    measure(gold)
    measure(pickaxe)

    return altitude_noise